#region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Osh.Configuration;
using Osh.Teletext;

namespace Osh.Dvb
{
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// References:
	///		ETSI EN 300 472 "Specification for conveying ITU-R System B Teletext in DVB bitstreams"
	///		ETSI EN 300 706 "Enhanced Teletext specification"
	///		ETSI EN 301 775 "Specification for the carriage of Vertical Blanking Information (VBI) data in DVB bitstreams"
	/// </remarks>
	public class TeletextPesReader
	{
		private const int PrivateStream1Id = 0xBD;
		private const int EbuTeletextNonSubtitleDataUnitId = 2;
		private const int EbuTeletextSubtitleDataUnitId = 3;
		private const int EbuTeletextPacketLength = 0x2C;	// 44
		private const int MaxNumberOfMagazines = 8;

		private Stream _steam;
		private IPacketStream _packetStream;
		private TeletextDecoder _teletextDecoder;

		public TeletextPesReader(Stream stream, TeletextService service)
		{
			_steam = stream;
			_packetStream = stream as IPacketStream;
			if(_packetStream == null)
				throw new ArgumentOutOfRangeException("stream", "Stream must implement IPacketStream interface.");
			_teletextDecoder = new TeletextDecoder(service);
		}

		public void ReadTeletextPackets()
		{
			byte[] buffer = _packetStream.PacketBuffer;
			int packetSize = _packetStream.PacketSize;
			int streamId = buffer[3];
			int pesPacketLength = (buffer[4] << 8) | buffer[5];
			int pesPacketHeaderLength = buffer[8];
			int payloadStart = 9 + pesPacketHeaderLength;
			byte dataIdentifier = buffer[payloadStart];	// data_identifier

			if(streamId != PrivateStream1Id)
				return;

			if((dataIdentifier >= 0x10 && dataIdentifier <= 0x1F) ||
				(dataIdentifier >= 0x99 && dataIdentifier <= 0x9B))
			{}
			else
				return;
			
			int ptsDtsFlags = (buffer[7] >> 6);	// PTS_DTS_flags
			Timestamp pts = Timestamp.Zero;
			if((ptsDtsFlags & 2) == 2)
				pts = DvbUtil.DecodeTimestamp(buffer, 9);

			int i = payloadStart + 1;
			while(i + 2 < packetSize)
			{
				int dataUnitId = buffer[i];	// data_unit_id
				int dataUnitLength = buffer[i+1];	// data_unit_length

				if(dataUnitId == EbuTeletextNonSubtitleDataUnitId ||
					dataUnitId == EbuTeletextSubtitleDataUnitId)
				{
					if(dataUnitLength == EbuTeletextPacketLength && (i + 2 + dataUnitLength <= packetSize))
					{
						_teletextDecoder.DecodePacket(pts.ToTimeSpan(), buffer, i + 4, EbuTeletextPacketLength - 2);
					}
				}

				i += 2 + dataUnitLength;
			}
		}

	}
}
